package cn.geekyspace.scanhive.infrastructure.scanner;

import cn.geekyspace.scanhive.infrastructure.ui.UILogger;
import com.fazecast.jSerialComm.SerialPort;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 扫描仪（扫码枪）串口管理
 */
@Data
@Slf4j
@Component
@RequiredArgsConstructor
@DependsOn("viewController")
public class ScannerSerialPortManager {

    /**
     * 已连接的串口映射表
     * - key：串口名称
     * - value：串口对象
     */
    private final Map<String, SerialPort> scannerPortMap = new ConcurrentHashMap<>();

    /**
     * 串口参数配置
     */
    private static final int BAUD_RATE = 115200;                                             // 波特率
    private static final int DATA_BITS = 8;                                                  // 数据位
    private static final int STOP_BITS = 1;                                                  // 停止位
    private static final int PARITY = 0;                                                     // 校验位 (0=无校验)
    private static final int READ_TIMEOUT = 1000;                                            // 读取超时时间 (ms)
    private static final String TARGET_PORT_NAME = "Prolific USB-to-Serial Comm Port";       // 扫码枪串口名称

    // 注入UI组件
    private final UILogger uiLogger;

    // 注入扫描仪（扫码枪）数据接收处理器
    private final ScannerDataReceiver scannerDataReceiver;


    /**
     * 定时扫描串口并连接目标串口
     */
    @Scheduled(fixedRate = 2000)
    public void scanAndConnectPorts() {
        if (uiLogger.getLogLabel() == null) {
            log.warn("logLabel 未注入，跳过扫码枪连接逻辑");
            return;
        }
        // 遍历当前系统的所有串口
        for (SerialPort port : SerialPort.getCommPorts()) {

            // 如果描述包含目标设备名，且未连接过，则尝试连接
            if (port.getDescriptivePortName().contains(TARGET_PORT_NAME)
                    && !scannerPortMap.containsKey(port.getSystemPortName())) {

                // 设置串口通信参数
                port.setComPortParameters(BAUD_RATE, DATA_BITS, STOP_BITS, PARITY);
                port.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, READ_TIMEOUT, 0);

                // 尝试打开串口
                if (port.openPort()) {

                    // 加入已连接集合
                    scannerPortMap.put(port.getSystemPortName(), port);
                    uiLogger.success("扫码枪连接成功: 串口 = " + port.getSystemPortName() + ", 描述 = " + port.getDescriptivePortName());

                    // ====================== 启动扫码数据接收线程 ======================
                    scannerDataReceiver.startReceivingData(port);
                } else {
                    uiLogger.warn("扫码枪连接失败: 串口 = " + port.getSystemPortName() + ", 描述 = " + port.getDescriptivePortName());
                }
            }
        }

        // 移除已断开的串口
        removeDisconnectedPorts();
    }

    /**
     * 检查并移除断开的串口
     */
    private void removeDisconnectedPorts() {
        // 遍历已连接的串口列表
        scannerPortMap.forEach((portName, port) -> {

            // 如果串口已经断开连接，移除该串口
            if (!port.isOpen()) {
                String disconnectMessage = "扫码枪连接断开: 串口 = " + port.getSystemPortName() + ", 串口 = " + port.getDescriptivePortName();
                uiLogger.error(disconnectMessage);

                // ====================== 停止扫码数据接收线程 ======================
                scannerDataReceiver.stopReceivingData();

                // 安全移除
                scannerPortMap.remove(portName);
            }
        });
    }

    /**
     * 释放资源
     */
    public void releaseResources() {
        scannerPortMap.values().forEach(port -> {
            if (port.isOpen()) {
                log.info("关闭扫码枪连接的串口: " + port.getSystemPortName());
                port.closePort();
            }
        });
        scannerPortMap.clear(); // 清空集合
    }

}
